home *** CD-ROM | disk | FTP | other *** search
/ The Best of MacTutor - S…e Code for Volumes 1 to 5 / The Best of MacTutor - Source Code for Volume 1-5 (Wayzata Technology)(6031)(1990).bin / Source Code / #42 (Mar 89) / XCMD CODE / XCMDADSP.inc < prev   
Text File  |  1989-01-11  |  13KB  |  554 lines

  1. (********************************)
  2. (*    file:        XCmdGlue.Inc                *)
  3. (*                                                            *)
  4. (* Support routines for  ADSP        *)
  5. (* Hypercard interface.                    *)
  6. (* ----------------------------    *)
  7. (* By:        Donald Koscheka                *)
  8. (* Date:    9-Jan-89                            *)
  9. (* All Rights Reserved                    *)
  10. (*                                                            *)
  11. (* ----------------------------    *)
  12. (********************************)
  13.  
  14.  
  15.  
  16. {**************************************}
  17. {*                                                                        *}
  18. {* Miscellaneous support routines            *}
  19. {*                                                                        *}
  20. {**************************************}
  21.  
  22.  
  23. FUNCTION RetrieveData( containerName : Str255 ): LongInt;
  24. {***************************
  25. * Given the name of a Hypercard
  26. * global container, return the 
  27. * data stored there as a long
  28. * Integer.
  29. *
  30. * Container data is a handle
  31. * to the contents of a global
  32. * container.  Theses contents
  33. * should contain the string
  34. * representation of a long integer
  35. * which we convert to pascal 
  36. * longInt.
  37. *
  38. * Since containerData is a
  39. * copy of the data, we must
  40. * dispose of it afterwards.
  41. ***************************}
  42. VAR
  43.     containerData    : Handle;
  44.     longStr                : Str255;
  45. BEGIN
  46.     ContainerData := GetGlobal( containerName );
  47.     
  48.     {***If the container is not empty, convert it    ***}
  49.     IF (ContainerData <> NIL) AND (ContainerData^ <> NIL) THEN
  50.     BEGIN
  51.         HLock( ContainerData );
  52.         ZeroToPas( ContainerData^, longStr );
  53.         RetrieveData := StrToLong( longStr );
  54.         HUnlock( ContainerData );
  55.         DisposHandle( ContainerData );
  56.     END;
  57. END;
  58.  
  59. FUNCTION StringToShort( str : Ptr ): INTEGER;
  60. {************************
  61. * Given a pointer to a "C" 
  62. * string, convert the number
  63. * to an integer and return
  64. * it to the caller
  65. ************************}
  66. VAR 
  67.     tempStr     : Str255;
  68. BEGIN
  69.     ZeroToPas( str, tempStr );
  70.     StringToShort := Integer(StrToNum(tempStr));
  71. END;
  72.  
  73.  
  74. Function StrCmp( s1, s2 : String ): Boolean;
  75. {***********************
  76. * Given two strings, return true 
  77. * if they match exactly, false
  78. * otherwise
  79. ***********************}
  80. VAR 
  81.     i,j                : Integer;
  82.     matching    : Boolean;
  83. BEGIN
  84.     matching := true;
  85.     i := Integer( s1[0] );    {*** the number of characters in string ***}
  86.     j := Integer( s2[0] );    {*** as well as the comparison string        ***}
  87.     IF i = j THEN                        {*** if not same length, not same string***}
  88.     WHILE i > 0 DO
  89.     BEGIN
  90.         WHILE matching DO
  91.             IF s1[i] <> s2[i] THEN {*** strings don't match        ***}
  92.                 BEGIN
  93.                     matching := false;
  94.                     i := 0;
  95.                 END;
  96.         i := i - 1;
  97.     END;
  98.     StrCmp := matching;
  99. END;
  100.  
  101.  
  102.  
  103. PROCEDURE p2cStr( myPtr : Ptr );
  104. {******************************
  105. * Convert a pascal string to a
  106. * 'c' string in place    
  107. ******************************}
  108. VAR
  109.     i     : LongInt;
  110.     aPtr: Ptr;
  111. BEGIN
  112.     FOR i := 0 to myPtr^ DO
  113.         BEGIN
  114.             aPtr := Pointer( ORD( myPtr ) + 1 );
  115.             myPtr^ := aPtr^;
  116.             myPtr := aPtr;
  117.         END;
  118.     myPtr := Pointer( ORD( myPtr ) - 1 );
  119.     myPtr^ := 0;
  120. END;
  121.  
  122.  
  123.  
  124. PROCEDURE TrashHandle( inH : Handle );
  125. {**********************
  126. * Unlock the input handle
  127. * and deallocate it    
  128. **********************}
  129. BEGIN
  130.     IF inH <> NIL THEN
  131.     BEGIN
  132.         HUnlock( inH );
  133.         DisposHandle( inH );
  134.     END;
  135. END;
  136.     
  137.     
  138. {**************************************}
  139. {*                                                                        *}
  140. {* Routines to access entities in the    *}
  141. {* names table                                                 *}
  142. {*                                                                        *}
  143. {**************************************}
  144.  
  145.  
  146. FUNCTION NBPGetAddress(    name : Ptr ): AddrBlock;
  147. {****************************
  148. * Given the name of an entity    
  149. * walk through the names table    
  150. * for the name and return            
  151. * the address if found, NIL         
  152. * otherwise                                        
  153. *                                                            
  154. ****************************}
  155. VAR
  156.     error        : Integer;
  157.     nbp            : NBPPtr;
  158.     found        : Boolean;
  159.     eName        : EntityName;
  160.     eAddr        : AddrBlock;    
  161.     who            : Integer;
  162.     str            : StringPtr;
  163.     pName        : Str255;
  164.  
  165. BEGIN
  166.     found     := FALSE;
  167.     who         := 1;
  168.     nbp         := NBPPtr( RetrieveData( 'GLOBALNBPDATA' ) );
  169.     IF ( nbp <> NIL ) AND (nbp^.LookUpBuffer <> NIL) THEN 
  170.     BEGIN
  171.         str         := StringPtr( @eName.objStr );
  172.         ZeroToPas( name, pName );
  173.         NBPGetAddress.aNet         := 0;
  174.         NBPGetAddress.aNode     := 0;
  175.         NBPGetAddress.aSocket := 0;
  176.     
  177.         HLock( Handle(nbp^.LookUpBuffer) );
  178.         IF (nbp^.EntCount > 0) THEN
  179.         REPEAT
  180.             error := NBPExtract(    Ptr(nbp^.LookUpBuffer^),
  181.                                                         nbp^.EntCount,who,eName,eAddr);
  182.              IF error = noErr THEN
  183.             BEGIN
  184.                 found := StringEqual(  str^, pName );
  185.                 IF found THEN
  186.                     NBPGetAddress := eAddr
  187.                 ELSE
  188.                     who := who + 1;
  189.                 IF (who > nbp^.EntCount) THEN found := TRUE;
  190.             END
  191.             ELSE
  192.                 found := TRUE;
  193.         UNTIL found;
  194.         HUnlock( Handle(nbp^.LookUpBuffer) );
  195.     END;
  196. END;
  197.  
  198.  
  199. FUNCTION NBPGetName( addr : AddrBlock ) : Handle;
  200. {***************************
  201. * Given the address of an entity,
  202. * walk through the names table
  203. * searching for the address and
  204. * return the name of the entity,
  205. * nil if not
  206. *
  207. ****************************}
  208. VAR
  209.     error        : Integer;
  210.     nbp            : NBPPtr;
  211.     done        : Boolean;
  212.     eName        : EntityName;
  213.     eAddr        : AddrBlock;    
  214.     who            : Integer;
  215.     yourName: Handle;
  216.  
  217. BEGIN
  218.     done         := FALSE;
  219.     who         := 1;
  220.     yourName:= NIL;
  221.     nbp         := NBPPtr( RetrieveData(  'GLOBALNBPDATA' ) );
  222.     
  223.     IF (nbp <> NIL) AND (nbp^.LookUpBuffer <> NIL) THEN 
  224.     BEGIN
  225.         HLock( nbp^.LookUpBuffer );
  226.         IF (nbp^.EntCount > 0) THEN
  227.         REPEAT
  228.             error := NBPExtract( nbp^.LookUpBuffer^,nbp^.EntCount,who,eName,eAddr);
  229.             IF error = noErr THEN
  230.             BEGIN
  231.                 IF LongInt(addr) = LongInt(eAddr) THEN
  232.                     yourName := PasToZero( eName.objStr )
  233.                 ELSE
  234.                     who := who + 1;
  235.                     
  236.                 IF (who > nbp^.EntCount) THEN
  237.                     done := TRUE;
  238.             END
  239.             ELSE
  240.                 done := TRUE;
  241.         UNTIL (done) OR (yourName <> NIL );
  242.             
  243.         HUnlock( nbp^.LookUpBuffer );
  244.     END;
  245.     NBPGetName := yourName;
  246. END;
  247.  
  248. {**************************************}
  249. {*                                                                        *}
  250. {* Routines to hangup and tear down a    *}
  251. {* connection                                                    *}
  252. {*                                                                        *}
  253. {**************************************}
  254.  
  255.  
  256. PROCEDURE DSPKillData( cb : cbPtr );
  257. (****************************************)
  258. (* Either we could not allocate enough    *)
  259. (* memory or the connection would not     *)
  260. (* initialize, dump all allocated data    *)
  261. (*                                                                            *)
  262. (* The input parameter, cb, points to        *)
  263. (* the block that we want to kill                *)
  264. (*                                                                             *)
  265. (****************************************)
  266. BEGIN
  267.     IF cb <> NIL THEN
  268.     WITH cb^ DO
  269.         BEGIN
  270.         {*** could not allocate or initialize ***}
  271.             IF sendQ <> NIL THEN DisposPtr( sendQ );
  272.             IF recvQ <> NIL THEN DisposPtr( recvQ );
  273.             IF attn  <> NIL THEN DisposPtr( attn );
  274.             
  275.             TrashHandle( remName     );
  276.             TrashHandle( msg             );
  277.             TrashHandle( inBuf         );
  278.             TrashHandle( outBuf     );
  279.             TrashHandle( attnBuf     );
  280.                 
  281.             DisposPtr( Ptr( cb ) );
  282.         END;
  283. END;
  284.  
  285.  
  286. PROCEDURE DSPDisConnect( cn : CBPtr );
  287. {***************************
  288. * Tear down an ADSP connection,
  289. * deallocate the memory and remove
  290. * the entity from the connection list.
  291. ***************************}
  292. VAR
  293.     nb, lb    : CBPtr;
  294.     dpb            : dspParamBlock;
  295.     tH            : Handle;
  296.     
  297. BEGIN
  298.     IF cn <> NIL THEN 
  299.     BEGIN
  300.         IF cn^.remName <> NIL THEN
  301.         BEGIN
  302.             SetGlobal( 'ADSPCaller', cn^.remName ); 
  303.             SendCardMessage( 'HungUp');
  304.         END;
  305.             
  306.         {***  remove connection from connection list    ***}
  307.         IF cn = adsp^.ends THEN {*** special case: cn = first ***}
  308.         BEGIN
  309.             adsp^.ends := cn^.next;
  310.             nb := cn^.next;
  311.             IF nb <> NIL THEN nb^.last := NIL;
  312.         END
  313.         ELSE
  314.         BEGIN
  315.             nb := cn^.next;
  316.             lb := cn^.last;
  317.             IF nb <> NIL THEN nb^.last := lb;
  318.             IF lb <> NIL THEN lb^.next := nb;
  319.         END;
  320.     
  321.         DSPKillData( cn );
  322.     END;
  323. END;    
  324.  
  325.  
  326.  
  327. FUNCTION DSPHangUp( cn : CBPtr ):OSErr;
  328. {***********************************
  329. * Hangup the line on requested 
  330. * connection end    
  331. *                                        
  332. *    ----------------------------------                                            
  333. * IN:    
  334. * pointer to the connection's block    
  335. *        handle to the data to send
  336. *                                            
  337. ***********************************}
  338. VAR
  339.     myPB    : DSPParamBlock;
  340.  
  341. BEGIN
  342.     IF cn <> NIL  THEN        {*** If the connection exists, tear it down    ***}
  343.     BEGIN
  344.         WITH myPB DO
  345.         BEGIN
  346.             ioCRefNum    := adsp^.dspRefNum;
  347.             ccbRefNum    := cn^.ccbRef;
  348.             csCode        := dspRemove;
  349.             abort        := -1;
  350.             
  351.             {*** Hangup synchronously because the state of the
  352.                 connection is about to go ballistic    ***}
  353.         END;
  354.         DSPHangup := PBControl( @myPB, SYNC );
  355.         DSPDisConnect( cn );
  356.     END;
  357. END;    
  358.  
  359.  
  360. {**************************************}
  361. {*                                                                        *}
  362. {* Routines to install a connection        *}
  363. {* and call a remote party.                        *}
  364. {*                                                                        *}
  365. {**************************************}
  366.  
  367. PROCEDURE DSPAddConnection( cb : CBPtr );
  368. {***************************
  369. * If we have a good connection, we can        
  370. * go ahead and put it into the    connection     
  371. * list.  It is either the first item in     
  372. * the list or we append it to the end by     
  373. * traversing the list to find the last item
  374. ****************************}
  375. VAR
  376.     nb, lb    : CBPtr;
  377. BEGIN
  378.     nb     := adsp^.ends;
  379.  
  380.     IF cb <> NIL THEN
  381.         IF nb = NIL THEN
  382.             adsp^.ends := cb
  383.         ELSE
  384.         BEGIN    
  385.             WHILE nb <> NIL DO {*** walk to the end of the list        ***}
  386.                 BEGIN
  387.                     lb := nb;
  388.                     nb := nb^.next;
  389.                 END;
  390.                 
  391.             lb^.next := cb;
  392.             cb^.next := NIL;
  393.             cb^.last := lb;
  394.         END;
  395. END;
  396.  
  397.  
  398. FUNCTION DSPCreate(    addr:AddrBlock; 
  399.                                         inBufSiz,    
  400.                                         outBufSiz,
  401.                                         retry,
  402.                                         interval    :Integer;
  403.                                         message        : Handle ): CBPtr;
  404. {******************************
  405. * Creates an ADSP connection, 
  406. * adds it to the  connection list,
  407. *
  408. *    -----------------------------                                        
  409. * IN:    
  410. * addr            : address of the entity
  411. *    inBufSiz, 
  412. * outBufSiz                
  413. *                        : size of the buffers
  414. *    retry            : number of times to 
  415. *                          retry the open    
  416. *    interval    : 10Xticks time to wait
  417. *                          between retries        
  418. * mess            : callback message        
  419. *    -----------------------------                                        
  420. * OUT:                                            
  421. * CBPtr            : return a pointer to
  422. *                          the connection, NIL if
  423. *                          connection not inited    
  424. *                                                
  425. ***********************************}
  426. VAR
  427.     error     : Integer;
  428.     siz            : LongInt;
  429.     cb            : CBPtr;
  430.     nbp            : NBPPtr;
  431.     haveIt    : BOOLEAN;
  432.     
  433. BEGIN
  434.         
  435.     cb := CBPtr(  NewPtr( SizeOf( Connection ) ));
  436.     IF cb <> NIL THEN 
  437.     WITH cb^ DO            {*** Allocate connection's structures    ***}
  438.         BEGIN
  439.             ccbRef    := 0;
  440.             msg        := NIL;
  441.             last     := NIL;
  442.             next     := NIL;
  443.             adr        := addr;    {*** address of the remote end     ***}
  444.             inBuf    := NIL;        {*** no data received yet                ***}
  445.             outBuf    := NIL;    {*** no data sent yet                        ***}
  446.             attnBuf    := NIL;    {*** no attention message...        ***}
  447.             mode    := NOP;        {*** connection not established    ***}
  448.             sendQ     := NewPtr( LongInt(outBufSiz) );
  449.             recvQ     := NewPtr( LongInt(inBufSiz) );
  450.             attn    := NewPtr( attnBufSize );
  451.             
  452.             {*** (3) Initialize the connection end                         ***}
  453.             IF (sendQ<>NIL) AND (recvQ<>NIL) AND (attn<>NIL) THEN
  454.             BEGIN
  455.                 IF message <> NIL THEN
  456.                 BEGIN
  457.                     siz    := GetHandleSize( message );
  458.                     msg    := NewHandle( siz );
  459.                     BlockMove( message^ , msg^, siz );
  460.                 END;
  461.                                     
  462.                 WITH attnPB DO 
  463.                 BEGIN
  464.                     userRoutine    := NIL;
  465.                     ioResult    := 1;    {*** mark it as busy***}
  466.                 END;
  467.                     
  468.                 ccb.userFlags := 0;
  469.                 
  470.                 WITH dspPB DO {*** Initialize the connection end ***}
  471.                 BEGIN
  472.                     csCode            := dspInit;
  473.                     ccbPtr            := @cb^.ccb;
  474.                     userRoutine    := NIL;
  475.                     ioCRefnum        := adsp^.dspRefNum;
  476.                     ioCompletion:= NIL;
  477.                     sendQSize        := outBufSiz;
  478.                     sendQueue        := sendQ;
  479.                     recvQueue        := recvQ;
  480.                     recvQSize        := inBufSiz;
  481.                     attnPtr            := attn;
  482.                     localSocket    := adsp^.addr.aSocket;
  483.                 END;
  484.                 error := PBControl( @cb^.dspPB, SYNC );
  485.                 
  486.                 IF error = noErr THEN {*** Add connection to list if init ok ***}
  487.                 BEGIN
  488.                     ccbRef    := dspPB.ccbRefNum;
  489.                     DSPAddConnection( cb );                                
  490.                 END
  491.                 ELSE    
  492.                     DSPKillData( cb );
  493.                 
  494.             END { IF data allocated OK }
  495.             ELSE{ data did not allocate or connection did not initialize }
  496.                 DSPKillData( cb );
  497.         END;        
  498.     DSPCreate := cb;
  499. END;    
  500.  
  501.  
  502. {**************************************}
  503. {*                                                                        *}
  504. {* Routines to send information over     *}
  505. {* the wire.                                                    *}
  506. {*                                                                        *}
  507. {**************************************}
  508.  
  509. FUNCTION DSPTalk(    cn : CBPtr; bufH : Handle ):OSErr;
  510. {********************************
  511. * Send the data to the requested 
  512. * connection end
  513. *                                        
  514. *                                                
  515. * IN:    pointer to the connection's block
  516. *            handle to the data to send                
  517. *                                                
  518. ********************************}
  519. VAR    
  520.     Hsiz    : LongInt;
  521.     
  522. BEGIN
  523.     {*** (1) Copy the data into a local buffer    ***}
  524.     cn^.outBuf := NIL; {*** assume we won't allocate the handle ***}
  525.     
  526.     IF bufH <> NIL THEN
  527.     BEGIN
  528.         HSiz := GetHandleSize( bufH );
  529.         cn^.outBuf := NewHandle( HSiz );
  530.     END;
  531.     
  532.     IF cn^.outBuf <> NIL THEN
  533.     BEGIN
  534.         MoveHHi( cn^.outBuf );
  535.         HLock( cn^.outBuf );
  536.         BlockMove( bufH^, cn^.outBuf^, HSiz );
  537.         
  538.         {*** (2) Send the data to the other end     ***}
  539.         WITH cn^.dspPB DO
  540.         BEGIN
  541.             ioCompletion:= NIL;
  542.             ioCRefNum     := adsp^.dspRefNum;
  543.             csCode         := dspWrite;
  544.             ccbRefNum    := cn^.ccbRef;
  545.             reqCount    := Integer( HSiz );
  546.             dataPtr        := cn^.outBuf^;
  547.             eom            := 1;
  548.             flush        := 1;
  549.         END;
  550.         DSPTalk := PBControl( @cn^.dspPB, ASYNC );
  551.     END;
  552. END;
  553.  
  554.